using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Input.Touch;


namespace Services
{
  public interface IInputManager
  {
    event InputManager.Tap OnDoubleTap;
    event InputManager.Tap OnTap;
    event InputManager.Tap OnPress;
    event InputManager.Tap OnDrag;
  }

  public class InputManager : Microsoft.Xna.Framework.GameComponent, IInputManager
  {
    static readonly float DOUBLE_TAP_INTERVAL = 0.2f;
    static readonly float SINGLE_TAP_INTERVAL = 0.2f;
    static readonly float LONG_TAP_INTERVAL = 0.3f;

    public InputManager(Game game)
      : base(game)
    {
      this.UpdateOrder = (int)ComponentOrders.INPUT;
      game.Services.AddService(typeof(IInputManager), this);
    }

    protected override void Dispose(bool disposing)
    {
      Game.Services.RemoveService(typeof(IInputManager));
      base.Dispose(disposing);
    }

    bool tap_pending = false;
    float time_since_last_release = 10000.0f;
    float time_since_last_press = 10000.0f;
    Vector2 pending_tap_position;

    Matrix screen_transform;
    public override void Initialize()
    {
      screen_transform = Matrix.CreateScale(Game.GraphicsDevice.Viewport.Width / 480.0f, Game.GraphicsDevice.Viewport.Height / 800.0f, 1.0f);

      base.Initialize();
    }

    bool mouse_pressed(MouseState mouse_state)
    {
#if WINDOWS || XBOX
      if (mouse_state.LeftButton == ButtonState.Pressed)
        return true;
#endif
      return false;
    }

    bool mouse_released(MouseState mouse_state)
    {
#if WINDOWS || XBOX
      if (mouse_state.LeftButton == ButtonState.Released)
        return true;
#endif
      return false;
    }

    bool skip_next_frame = false;
    MouseState prev_mouse_state = new MouseState();
    public override void Update(GameTime gameTime)
    {
      var dt = (float)gameTime.ElapsedGameTime.TotalSeconds;

      var mouse_state = Mouse.GetState();
      //if (mouse_state.RightButton == ButtonState.Released &&
      //   prev_mouse_state.RightButton == ButtonState.Pressed)
      //  if (OnPress != null)
      //    OnPress(new Vector2(mouse_state.X, mouse_state.Y));

      time_since_last_release += dt;
      var touches = TouchPanel.GetState();
      if (touches.Any(t => t.State == TouchLocationState.Released) || mouse_released(mouse_state))
      {
        time_since_last_release = 0.0f;
      }

      time_since_last_press += dt;
      var pressed = touches.Any(t => t.State != TouchLocationState.Released) || mouse_pressed(mouse_state);
      if (pressed && tap_pending == false && skip_next_frame == false)
      {
        time_since_last_press = 0.0f;
        tap_pending = true;
#if WINDOWS || XBOX
        pending_tap_position = new Vector2(mouse_state.X, mouse_state.Y);
#else
        pending_tap_position = touches.First(t => t.State != TouchLocationState.Released).Position;
#endif
      }
      skip_next_frame = false;

      if (pressed && tap_pending && time_since_last_press > LONG_TAP_INTERVAL)
      {
        tap_pending = false;
        skip_next_frame = true;
        //System.Diagnostics.Debug.WriteLine("press");
        if (OnPress != null)
          OnPress(pending_tap_position);
      }
      else if (pressed && tap_pending && time_since_last_release < DOUBLE_TAP_INTERVAL && time_since_last_release < time_since_last_press)
      {
        //System.Diagnostics.Debug.WriteLine("double tap");
        tap_pending = false;
        skip_next_frame = true;
#if WINDOWS || XBOX
          var p = new Vector2(mouse_state.X, mouse_state.Y);
#else
        var p = touches.First(t => t.State != TouchLocationState.Released).Position;
#endif
        if (OnDoubleTap != null)
          OnDoubleTap(p);
      }
      else if (pressed == false && tap_pending && time_since_last_press > SINGLE_TAP_INTERVAL)
      {
        //System.Diagnostics.Debug.WriteLine("tap");
        tap_pending = false;
        if (OnTap != null)
          OnTap(pending_tap_position);
      }

      if (pressed && OnDrag != null)
      {
#if WINDOWS || XBOX
        var drag_position = new Vector2(mouse_state.X, mouse_state.Y);
#else
        var drag_position = touches.First(t => t.State != TouchLocationState.Released).Position;
#endif
        OnDrag(drag_position);
      }
      prev_mouse_state = mouse_state;
      base.Update(gameTime);
    }

    public delegate void Tap(Vector2 tap_position);
    public event Tap OnTap;
    public event Tap OnDoubleTap;
    public event Tap OnPress;
    public event Tap OnDrag;
  }
}
